package com.wx.wechat.service.impl;

import com.wx.commons.utils.enums.EnumsUtils;
import com.wx.core.exception.BusinessJsonException;
import com.wx.wechat.Interface.WeChatOatuh;
import com.wx.wechat.config.WeChatConfig;
import com.wx.wechat.enums.status.WeChatEnumStatus;
import com.wx.wechat.response.WeChatCode2Session;
import com.wx.wechat.response.WeChatOauth2AccessToken;
import com.wx.wechat.response.WeChatUser;
import com.wx.wechat.service.WeChatOatuhService;
import com.wx.wechat.utils.URIUtil;
import lombok.extern.slf4j.Slf4j;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import static com.wx.wechat.config.WechatAPI.DOMAIN_MP;
import static com.wx.wechat.constant.WechatParameterName.WechatRequest.*;
import static com.wx.wechat.constant.WechatParameterName.WechatResponse.RESPONSE_ERRCODE;
import static com.wx.wechat.enums.status.WeChatEnumStatus.WeChatLang.ZH_CN;

/**
 * @author wx
 * @Description: 微信授权业务层
 * @date 2018/11/6 000612:00
 */
@Slf4j
public class WeChatOatuhServiceImpl implements WeChatOatuhService {
    private WeChatConfig weChatConfig;

    public void setWeChatConfig(WeChatConfig weChatConfig) {
        this.weChatConfig = weChatConfig;
    }


    /**
     * @param redirectURI 重定向地址
     * @param scope       应用授权作用域 1.snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid） 2.snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且， 即使在未关注的情况下，只要用户授权，也能获取其信息 ）
     * @param state       重定向后会带上state参数
     * @description: 微信oauth2授权
     * @author: wx
     * @date: 2018/11/6
     * @return: url redirectURI + code=CODE&state=STATE
     */
    @Override
    public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) throws BusinessJsonException {
        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Map<String, String> parameMap = new LinkedHashMap<>();
        parameMap.put(REQUEST_APP_ID, weChatConfig.getAppId());
        parameMap.put(REQUEST_REDIRECT_URI, URIUtil.encodeURIComponent(redirectURI));
        parameMap.put(REQUEST_RESPONSE_TYPE, "code");
        parameMap.put(REQUEST_SCOPE, scope);
        parameMap.put(REQUEST_STATE, state + "#wechat_redirect");
        Call<String> stringCall = retrofit.create(WeChatOatuh.class).oauth2buildAuthorizationUrl(parameMap);
        try {
            String responseBodyString = stringCall.execute().body();
            return responseBodyString;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信oauth2授权失败");
        }
    }

    /**
     * @param code
     * @description: 用code换取oauth2的AccessToken
     * @author: wx
     * @date: 2018/11/6 0006
     * @return: com.wx.wechat.response.WechatMpOauth2AccessToken
     */
    @Override
    public WeChatOauth2AccessToken oauth2getAccessToken(String code) throws BusinessJsonException {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(DOMAIN_MP)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Map<String, String> parameMap = new LinkedHashMap<>();
        parameMap.put(REQUEST_APP_ID, weChatConfig.getAppId());
        parameMap.put(REQUEST_SECRET, weChatConfig.getSecret());
        parameMap.put(REQUEST_CODE, code);
        parameMap.put(REQUEST_GRANT_TYPE, "authorization_code");
        Call<WeChatOauth2AccessToken> weChatOauth2AccessTokenCall = retrofit.create(WeChatOatuh.class).oauth2getAccessToken(parameMap);
        try {
            WeChatOauth2AccessToken weChatOauth2AccessToken = weChatOauth2AccessTokenCall.execute().body();
            return weChatOauth2AccessToken;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信获取AccessToken失败");
        }
    }


    /**
     * @param refreshToken
     * @description: 刷新oauth2的AccessToken
     * @author: wx
     * @date: 2018/11/6 0006
     * @return: com.wx.wechat.response.WechatMpOauth2AccessToken
     */
    @Override
    public WeChatOauth2AccessToken oauth2refreshAccessToken(String refreshToken) throws BusinessJsonException {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(DOMAIN_MP)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Map<String, String> parameMap = new LinkedHashMap<>();
        parameMap.put(REQUEST_APP_ID, weChatConfig.getAppId());
        parameMap.put(REQUEST_GRANT_TYPE, "refresh_token");
        parameMap.put(REQUEST_REFRESH_TOKEN, refreshToken);
        Call<WeChatOauth2AccessToken> weChatOauth2AccessTokenCall = retrofit.create(WeChatOatuh.class).oauth2refreshAccessToken(parameMap);
        try {
            WeChatOauth2AccessToken weChatOauth2AccessToken = weChatOauth2AccessTokenCall.execute().body();
            return weChatOauth2AccessToken;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信刷新AccessToken失败");
        }
    }

    /**
     * @param weChatOauth2AccessToken
     * @param lang                    语言 1 简体，2 繁体，3 英语
     * @description: 获取微信用户信息
     * @author: wx
     * @date: 2018/11/6 0006
     * @return: com.wx.wechat.response.WechatUser
     */
    @Override
    public WeChatUser oauth2getUserInfo(WeChatOauth2AccessToken weChatOauth2AccessToken, Integer lang) throws BusinessJsonException {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(DOMAIN_MP)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Map<String, String> parameMap = new LinkedHashMap<>();
        parameMap.put(REQUEST_ACCESS_TOKEN, weChatOauth2AccessToken.getAccessToken());
        parameMap.put(REQUEST_OPEN_ID, weChatOauth2AccessToken.getOpenId());
        parameMap.put(REQUEST_LANG,lang == null ? ZH_CN.getMessage() : EnumsUtils.getEnumMeesge(WeChatEnumStatus.WeChatLang.class,lang));
        Call<WeChatUser> weChatUserCall = retrofit.create(WeChatOatuh.class).oauth2getUserInfo(parameMap);
        try {
            WeChatUser weChatUser = weChatUserCall.execute().body();
            return weChatUser;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("获取微信用户信息失败");
        }
    }


    /**
     * @description: 验证AccessToken是否有效
     * @author: wx
     * @date: 2018/11/6 0006
     * @param weChatOauth2AccessToken
     * @return: boolean
     */
    @Override
    public Boolean oauth2validateAccessToken(WeChatOauth2AccessToken weChatOauth2AccessToken) {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(DOMAIN_MP)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Call<Map<String, String>> mapCall = retrofit.create(WeChatOatuh.class).oauth2validateAccessToken(weChatOauth2AccessToken.getAccessToken(), weChatOauth2AccessToken.getOpenId());
        try {
            Map<String, String> body = mapCall.execute().body();
            if (Objects.equals(body.get(RESPONSE_ERRCODE),"0")){
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("验证AccessToken失败");
        }
    }

    /**
     * @description: 微信小程序登录凭证校验(获取微信用户openid)
     * @author: wx
     * @date: 2018/11/6 0006
     * @param code
     * @return: com.wx.wechat.response.WeChatCode2Session
     */
    @Override
    public WeChatCode2Session code2Session(String code) throws BusinessJsonException {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(DOMAIN_MP)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        Map<String, String> parameMap = new LinkedHashMap<>();
        parameMap.put(REQUEST_APP_ID, weChatConfig.getAppId());
        parameMap.put(REQUEST_SECRET, weChatConfig.getSecret());
        parameMap.put(REQUEST_JS_CODE, code);
        parameMap.put(REQUEST_GRANT_TYPE, "authorization_code");
        Call<WeChatCode2Session> weChatCode2SessionCall = retrofit.create(WeChatOatuh.class).code2Session(parameMap);
        try {
            WeChatCode2Session weChatCode2Session = weChatCode2SessionCall.execute().body();
            return weChatCode2Session;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信小程序登录凭证校验(获取微信用户openid)失败");
        }
    }
}
